/* Echo
   (c)2002 Trilinear
*/



#include "echo.h"

#ifdef WIN32

#endif


#include "level1.h"
#include "level3.h"
#include "level5.h"
#include "title.h"
#include "collmap.h"

//#define MOVIEMAKER
#define SCREENSHOTMAKER

#define DEGTORAD 0.0174532f
#define RADTODEG 57.2957795f

#define UMAX 6.0f
#define VMAX 3.0f
#define SDIFF 0.003f
#define SDIF2 0.005f
#define UDIFF (1.0f/6.0f)-SDIFF
#define VDIFF (1.0f/3.0f)-SDIFF

#define STDSTART 0
#define STDEND 9
#define CLIMBSTART 10
#define CLIMBMID 20
#define CLIMBEND 29
#define JOGSTART 30
#define JOGMID 35
#define JOGEND 41
#define JUMPSTART 42
#define JUMPEND 66
#define PUSHSTART 67
#define PUSHMID 71
#define PUSHEND 76
#define DIESTART 77
#define DIEEND 92
#define FRAMEMAX 92

#define MMSTAND 0
#define MMCLIMB 1
#define MMWALK 2
#define MMJOG 3
#define MMJUMP 4
#define MMPUSH 5
#define MMDIE 6

#define PGUNWALKSTART 0
#define PGUNWALKEND 36
#define PGUNEXPLSTART 37
#define PGUNEXPLEND 68

#define MAP_WIDTH 400
#define MAP_HEIGHT 50
#define GRAVITY 0.070f
#define JUMPVEL -0.40f
#define JUMPACCTIME 8
#define TERMVEL 0.9f
#define MAXVELX 0.4f
#define RUNVELX 0.4f
#define AIRFRICTION 0.9f
#define BOUNCEFRICTION 0.99f
#define CLIMBSPEED 0.2f

#define VALUECOIN 10
#define VALUEPGUN 50

#define MAXINACTIVETIME 150
#define BLINKTIME 5


#define TEXCOUNT 8
agmmodel mod_echo,mod_sky,mod_pgun;
tgmmodel mod_tiles,mod_ground,mod_items;

typedef struct {
	vector pos;
	vector vel;
	int dying;
	int jumping;
	int pushing;
	int climbing;
	int canjump;
	int jumppush;
	int hitblock;
	int movemode;
	int flip;
} herotype;

typedef struct {
	float x,y,z,rx,ry,zoom;
} mycamtype;

short tilemap[MAP_WIDTH*MAP_HEIGHT];
char collmap[256];

herotype echo;
mycamtype cam;

#define MAXMOVIETIME 1800
#define MOVIEMAGIC (('E') | ('M'<<8) | ('O'<<16) | ('V'<<24))
uint16 moviecond[MAXMOVIETIME];

typedef struct {
	int Magic;
	int framecount;
} movieheadertype;

time_t curtime,oldtime;
int button;
int sound_jump,sound_land,sound_walk,sound_tick,sound_explode,sound_die,sound_switch;
int sound_bumpup,sound_coin,sound_slide,sound_bumpbox,sound_cash;

int inactivetime,blinkcount;
int score,lives;
char recordmovie;
char playmovie;
int movietime;
int currentmaxmovietime;
int loadlevel=0;
char showpanel=0;

#ifdef SCREENSHOTMAKER
char takeshot=0;
#endif

GLuint	tex_echo,tex_echoblink,tex_bg,tex_sky,tex_pgun,tex_path,tex_tile[TEXCOUNT],tex_ground[TEXCOUNT],tex_panel;

typedef struct {
	vector pos;
	float curFrame;
	char flip;
	char type;
	char active;
	char exploding;
} enemytype;

typedef struct {
	vector pos;
	vector vel;
	float width;
	float height;
	char type;
	char model;
	char active;
	char usegravity;
	char bounce;
	char pushable;
	char movableleft;
	char movableright;
} itemtype;

#define ENEMYCOUNT 16
#define ITEMCOUNT 140
enemytype enemies[ENEMYCOUNT];
itemtype items[ITEMCOUNT];


void InitEnemies()
{
	int i,x,y,count=0;
	for (i=0;i<ENEMYCOUNT;i++) {
/*		vector pos;
		float curFrame;
		char flip;
		char type;
		char active;
		char exploding;
*/		enemies[i].pos.x=enemies[i].pos.y=enemies[i].pos.z=0;
		enemies[i].curFrame=0;
		enemies[i].flip=1;
		enemies[i].type=0;
		enemies[i].active=0;
		enemies[i].exploding=0;	
	}
	for (x=0;x<MAP_WIDTH;x++) {
		for (y=0;y<MAP_HEIGHT;y++) {
			if ((tilemap[x+y*MAP_WIDTH]&0xFF)==12) {//pgun
				enemies[count].pos.x=(float)x;
				enemies[count].pos.z=(float)y+1.0f;
				enemies[count].type=1;
				enemies[count].active=1;
				count++;
				if (count>=ENEMYCOUNT) count=ENEMYCOUNT-1;
			}
		}
	}
}

inline void InitItem(int i) {
/*	vector pos;
	vector vel;
	float width;
	float height;
	char type;
	char model;
	char active;
	char usegravity;
	char bounce;
	char pushable;
	char movableleft;
	char movableright;
*/
	items[i].pos.x=items[i].pos.y=items[i].pos.z=0;
	items[i].vel.x=items[i].vel.y=items[i].vel.z=0;
	items[i].width=2;
	items[i].height=2;
	items[i].type=0;
	items[i].model=0;
	items[i].active=0;
	items[i].usegravity=0;
	items[i].bounce=0;
	items[i].pushable=0;
	items[i].movableleft=0;
	items[i].movableright=0;
}

void InitItems()
{
	int i,x,y,count=0;
	for (i=0;i<ITEMCOUNT;i++) {
		InitItem(i);
	}
	for (x=0;x<MAP_WIDTH;x++) {
		for (y=0;y<MAP_HEIGHT;y++) {
			if ((tilemap[x+y*MAP_WIDTH]&0xFF)==108) {//coin
				items[count].pos.x=(float)x-.5f;
				items[count].pos.z=(float)y+1.0f;
				items[count].type=1;
				items[count].model=1;
				items[count].bounce=1;
				items[count].active=1;
				count++;
				if (count>=ITEMCOUNT) count=ITEMCOUNT-1;
			}
			if ((tilemap[x+y*MAP_WIDTH]&0xFF)==172) {//box
				items[count].pos.x=(float)x-.5f;
				items[count].pos.z=(float)y+1.0f;
				items[count].type=2;
				items[count].model=2;
				items[count].active=1;
				items[count].pushable=1;
				items[count].width=4;
				items[count].height=4;
				items[count].movableleft=1;
				items[count].movableright=1;
				items[count].usegravity=1;
				count++;
				if (count>=ITEMCOUNT) count=ITEMCOUNT-1;
			}
			if ((tilemap[x+y*MAP_WIDTH]&0xFF)>=252) {//letterbox
				items[count].pos.x=(float)x-.5f;
				items[count].pos.z=(float)y+1.0f;
				items[count].type=2;
				items[count].model=(tilemap[x+y*MAP_WIDTH]&0xFF)-249;
				items[count].active=1;
				items[count].pushable=1;
				items[count].width=4;
				items[count].height=4;
				items[count].movableleft=1;
				items[count].movableright=1;
				items[count].usegravity=1;
				count++;
				if (count>=ITEMCOUNT) count=ITEMCOUNT-1;
			}
		}
	}
}

int ItemOpenSlot()
{
	int i;
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active==0) {
			return i;
		}
	}
	return ITEMCOUNT-1;
}


void restartlevel() {
/*
	vector pos;
	vector vel;
	int dying;
	int jumping;
	int pushing;
	int climbing;
	int canjump;
	int jumppush;
	int hitblock;
	int movemode;
	int flip;
*/
	int x,y;
	echo.pos.x = 10.0f;
	echo.pos.y = 0.0f;
	echo.pos.z = 40.0f;
	for (x=0;x<MAP_WIDTH;x++) {
		for (y=0;y<MAP_HEIGHT;y++) {
			if ((tilemap[x+y*MAP_WIDTH]&0xFF)==13) {//echo start
				echo.pos.x=(float)x+1.0f;
				echo.pos.z=(float)y+1.0f;
			}
		}
	}
	echo.vel.x=echo.vel.y=echo.vel.z = 0.0f;
	echo.dying=0;
	echo.jumping=0;
	echo.pushing=0;
	echo.climbing=0;
	echo.canjump=1;
	echo.jumppush=0;
	echo.hitblock=0;
	echo.movemode=MMSTAND;
	echo.flip=1;

	cam.x = echo.pos.x;
	cam.z = echo.pos.z;
	cam.ry = 0.0f;
	cam.zoom = 40.0f;

}

void resetlevel() {
	int i;

	for (i=0;i<MAP_WIDTH*MAP_HEIGHT;i++) {
		if (loadlevel==0) {
			tilemap[i]=title_map[i];
		}else if (loadlevel==1) {
			tilemap[i]=lev1_map[i];
		}else if (loadlevel==3) {
			tilemap[i]=lev3_map[i];
		}else if (loadlevel==5) {
			tilemap[i]=lev5_map[i];
		}else{
			tilemap[i]=lev3_map[i];
		}
	}
	for (i=0;i<256;i++) {
		collmap[i]=extcollmap[i];
	}

	InitEnemies();
	InitItems();
	restartlevel();


}

void initgame() {
//	rtc = (vuint32*)0xa0710000;
	snd_stream_init( NULL );

	sound_jump=snd_sfx_load( ROMDISKDIR "jump.aud" );
	sound_land=snd_sfx_load( ROMDISKDIR "land.aud" );
	sound_walk=snd_sfx_load( ROMDISKDIR "walk.aud" );
	sound_tick=snd_sfx_load( ROMDISKDIR "tick.aud" );
	sound_explode=snd_sfx_load( ROMDISKDIR "metal.aud" );
	sound_die=snd_sfx_load( ROMDISKDIR "die.aud" );
	sound_switch=snd_sfx_load( ROMDISKDIR "switch.aud" );
	sound_bumpup=snd_sfx_load( ROMDISKDIR "bumpup.aud" );
	sound_coin=snd_sfx_load( ROMDISKDIR "coin.aud" );
	sound_slide=snd_sfx_load( ROMDISKDIR "slidebox.aud" );
	sound_bumpbox=snd_sfx_load( ROMDISKDIR "bumpbox.aud" );
	sound_cash=snd_sfx_load( ROMDISKDIR "cash.aud" );

	load_agm(ROMDISKDIR "echo.agm",&mod_echo);
	load_agm(ROMDISKDIR "sky.agm",&mod_sky);
	load_agm(ROMDISKDIR "pgun.agm",&mod_pgun);

	load_tgm(ROMDISKDIR "tiles.tgm",&mod_tiles);
	load_tgm(ROMDISKDIR "items.tgm",&mod_items);

	/* Load a texture */
	loadjpg(ROMDISKDIR "echo.txr", 512, &tex_echo);
	loadjpg(ROMDISKDIR "echoblink.txr", 512, &tex_echoblink);
	loadjpg(ROMDISKDIR "sky.txr", 256, &tex_sky);

	if (loadlevel==0) {
		load_tgm(ROMDISKDIR "groundt.tgm",&mod_ground);
		loadjpg(ROMDISKDIR "grass.txr", 256, &tex_ground[0]);
		loadjpg(ROMDISKDIR "path.txr", 256, &tex_ground[1]);
		loadjpg(ROMDISKDIR "Alumox.txr", 256, &tex_ground[2]);
		loadjpg(ROMDISKDIR "sign.txr", 256, &tex_ground[3]);
		loadjpg(ROMDISKDIR "wood.txr", 256, &tex_ground[4]);
		loadjpg(ROMDISKDIR "start.txr", 256, &tex_ground[5]);
	}else if (loadlevel==1){
		load_tgm(ROMDISKDIR "ground1.tgm",&mod_ground);
		loadjpg(ROMDISKDIR "path.txr", 256, &tex_ground[1]);
		loadjpg(ROMDISKDIR "grass.txr", 256, &tex_ground[0]);
	}else if (loadlevel==3) {
		load_tgm(ROMDISKDIR "ground3.tgm",&mod_ground);
		loadjpg(ROMDISKDIR "path.txr", 256, &tex_ground[1]);
		loadjpg(ROMDISKDIR "grass.txr", 256, &tex_ground[0]);
		loadjpg(ROMDISKDIR "Alumox.txr", 256, &tex_ground[2]);
		loadjpg(ROMDISKDIR "wood.txr", 256, &tex_ground[3]);
	}else if (loadlevel==5) {
		load_tgm(ROMDISKDIR "ground5.tgm",&mod_ground);
		loadjpg(ROMDISKDIR "brickwall.txr", 256, &tex_ground[0]);
	}else {
		load_tgm(ROMDISKDIR "ground3.tgm",&mod_ground);
		loadjpg(ROMDISKDIR "path.txr", 256, &tex_ground[1]);
		loadjpg(ROMDISKDIR "grass.txr", 256, &tex_ground[0]);
		loadjpg(ROMDISKDIR "Alumox.txr", 256, &tex_ground[2]);
		loadjpg(ROMDISKDIR "wood.txr", 256, &tex_ground[3]);
	}

	loadjpg(ROMDISKDIR "pgun.txr", 256, &tex_pgun);
//	loadpng(ROMDISKDIR "echotile.txa",PNG_FULL_ALPHA, &tex_tile[0]);
	loadjpg(ROMDISKDIR "echotile.txr", 256, &tex_tile[0]);
	loadpng(ROMDISKDIR "panel.txa",PNG_FULL_ALPHA, &tex_panel);
	currentmaxmovietime=0;
	movietime=0;
	inactivetime=0;
	blinkcount=0;
	button=0;
	resetlevel();
//	oldtime = rtc[1]&0xFFFF;//timer_count(TMU0);
	c = maple_first_controller();
}

void killgame() {
	free_agm(&mod_echo);
	free_agm(&mod_sky);
	free_agm(&mod_pgun);
	
	free_tgm(&mod_tiles);
	free_tgm(&mod_ground);
	
	snd_sfx_unload_all();
	snd_stream_shutdown();
	
	glDeleteTextures(1, &tex_echo);
	glDeleteTextures(1, &tex_echoblink);
	glDeleteTextures(1, &tex_sky);
	if (loadlevel==0) {
		glDeleteTextures(1,  &tex_ground[0]);
		glDeleteTextures(1, &tex_ground[1]);
		glDeleteTextures(1, &tex_ground[2]);
		glDeleteTextures(1, &tex_ground[3]);
		glDeleteTextures(1, &tex_ground[4]);
		glDeleteTextures(1, &tex_ground[5]);
	}else if (loadlevel==1){
		glDeleteTextures(1, &tex_ground[1]);
		glDeleteTextures(1, &tex_ground[0]);
	}else if (loadlevel==3){
		glDeleteTextures(1, &tex_ground[1]);
		glDeleteTextures(1, &tex_ground[0]);
		glDeleteTextures(1, &tex_ground[2]);
		glDeleteTextures(1, &tex_ground[3]);
	}else if (loadlevel==5){
		glDeleteTextures(1, &tex_ground[0]);
	}else {
		glDeleteTextures(1, &tex_ground[1]);
		glDeleteTextures(1, &tex_ground[0]);
		glDeleteTextures(1, &tex_ground[2]);
		glDeleteTextures(1, &tex_ground[3]);
	}
	glDeleteTextures(1, &tex_pgun);
	glDeleteTextures(1, &tex_tile[0]);
	glDeleteTextures(1, &tex_panel);
}

void SwitchBlocks(int On)
{
	int x,y;
	for (x=0;x<MAP_WIDTH;x++) {
		for (y=0;y<MAP_HEIGHT;y++) {
			if (On==1 && tilemap[x+y*MAP_WIDTH]==114) {
				tilemap[x+y*MAP_WIDTH]=370;
			}
			if (On==1 && tilemap[x+y*MAP_WIDTH]==44) {
				tilemap[x+y*MAP_WIDTH]=300;
			}
			if (On==1 && tilemap[x+y*MAP_WIDTH]==45) {
				tilemap[x+y*MAP_WIDTH]=301;
			}
			if (On==0 && tilemap[x+y*MAP_WIDTH]==370) {
				tilemap[x+y*MAP_WIDTH]=114;
			}
			if (On==0 && tilemap[x+y*MAP_WIDTH]==300) {
				tilemap[x+y*MAP_WIDTH]=44;
			}
			if (On==0 && tilemap[x+y*MAP_WIDTH]==301) {
				tilemap[x+y*MAP_WIDTH]=45;
			}
		}
	}
	if (On==1) {
		collmap[98]=C_ALL;
		collmap[99]=C_ALL;
		collmap[114]=C_ALL;
		collmap[115]=C_ALL;
	}
	if (On==0) {
		collmap[98]=C_NONE;
		collmap[99]=C_NONE;
		collmap[114]=C_NONE;
		collmap[115]=C_NONE;
	}
	snd_sfx_play(sound_switch, 240, 128 );
}

void ItemBlocks()
{
	int OpenSlot;
	uint32 w=((uint32)(echo.pos.x-.5f));
	uint32 h=((uint32)(echo.pos.z));
	
	h-=4;

	if (tilemap[w+h*MAP_WIDTH]==112 ) {
		tilemap[w+h*MAP_WIDTH]=0;
		tilemap[(w+1)+h*MAP_WIDTH]=0;
		tilemap[w+(h-1)*MAP_WIDTH]=0;
		tilemap[(w+1)+(h-1)*MAP_WIDTH]=0;
		OpenSlot=ItemOpenSlot();
		InitItem(OpenSlot);
		items[OpenSlot].pos.x=((float)w)-0.5f;
		items[OpenSlot].pos.z=((float)h)+1.0f;
		items[OpenSlot].usegravity=1;
		items[OpenSlot].bounce=1;
		items[OpenSlot].vel.z=-1.0f;
		items[OpenSlot].active=1;
		items[OpenSlot].type=1;
		items[OpenSlot].model=1;
		items[OpenSlot].width=2;
		items[OpenSlot].width=2;
	};
	if (tilemap[(w+1)+h*MAP_WIDTH]==113) {
		tilemap[w+h*MAP_WIDTH]=0;
		tilemap[(w+1)+h*MAP_WIDTH]=0;
		tilemap[w+(h-1)*MAP_WIDTH]=0;
		tilemap[(w+1)+(h-1)*MAP_WIDTH]=0;
		OpenSlot=ItemOpenSlot();
		InitItem(OpenSlot);
		items[OpenSlot].pos.x=((float)w)-0.5f;
		items[OpenSlot].pos.z=((float)h)+1.0f;
		items[OpenSlot].usegravity=1;
		items[OpenSlot].bounce=1;
		items[OpenSlot].vel.z=-1.0f;
		items[OpenSlot].active=1;
		items[OpenSlot].type=1;
		items[OpenSlot].model=1;
		items[OpenSlot].width=2;
		items[OpenSlot].width=2;
	};
	if (tilemap[w+h*MAP_WIDTH]==113) {
		tilemap[w+h*MAP_WIDTH]=0;
		tilemap[(w-1)+h*MAP_WIDTH]=0;
		tilemap[w+(h-1)*MAP_WIDTH]=0;
		tilemap[(w-1)+(h-1)*MAP_WIDTH]=0;
		OpenSlot=ItemOpenSlot();
		InitItem(OpenSlot);
		items[OpenSlot].pos.x=((float)w)-1.5f;
		items[OpenSlot].pos.z=((float)h)+1.0f;
		items[OpenSlot].usegravity=1;
		items[OpenSlot].bounce=1;
		items[OpenSlot].vel.z=-1.0f;
		items[OpenSlot].active=1;
		items[OpenSlot].type=1;
		items[OpenSlot].model=1;
		items[OpenSlot].width=2;
		items[OpenSlot].width=2;
	};
	if (tilemap[(w+1)+h*MAP_WIDTH]==112) {
		tilemap[(w+1)+h*MAP_WIDTH]=0;
		tilemap[(w+2)+h*MAP_WIDTH]=0;
		tilemap[(w+1)+(h-1)*MAP_WIDTH]=0;
		tilemap[(w+2)+(h-1)*MAP_WIDTH]=0;
		OpenSlot=ItemOpenSlot();
		InitItem(OpenSlot);
		items[OpenSlot].pos.x=((float)w)+0.5f;
		items[OpenSlot].pos.z=((float)h)+1.0f;
		items[OpenSlot].usegravity=1;
		items[OpenSlot].bounce=1;
		items[OpenSlot].vel.z=-1.0f;
		items[OpenSlot].active=1;
		items[OpenSlot].type=1;
		items[OpenSlot].model=1;
		items[OpenSlot].width=2;
		items[OpenSlot].width=2;
	};
	snd_sfx_play(sound_coin, 240, 128 );
}

inline int OnEnemyHead() 
{
	int i;
	for (i=0;i<ENEMYCOUNT;i++) {
		if (enemies[i].active==1) {
			if (enemies[i].pos.x>(echo.pos.x-2.0f) && enemies[i].pos.x<(echo.pos.x+1.0f) 
							&& echo.dying==0 && enemies[i].exploding==0) {
				
				if (enemies[i].pos.z>(echo.pos.z+2.0f) && enemies[i].pos.z<(echo.pos.z+3.0f)
							&& echo.vel.z>=0  ) {
					enemies[i].curFrame=PGUNEXPLSTART;
					enemies[i].exploding=1;
					echo.movemode=MMJUMP;
					mod_echo.curFrame=JUMPSTART;
					echo.jumping=1;
					echo.jumppush=1;
					echo.vel.z=2*JUMPVEL;
					echo.pos.z+=echo.vel.z;
					echo.canjump=0;
					snd_sfx_play(sound_explode, 255, 128 );
					score+=VALUEPGUN;//congrats, you've killed an enemy!

					return i;
				}else if (enemies[i].pos.z>(echo.pos.z-2.0f) && enemies[i].pos.z<(echo.pos.z+2.0f) ) {
					echo.dying=1;
					mod_echo.curFrame=DIESTART;
					snd_sfx_play(sound_die, 255, 128 );//enemy has killed you!
					lives-=1;
				}
			}
		}
	}
	return -1;
}

inline int OnGround(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	
	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_UP)==C_UP) {
		return tilemap[w+(h)*MAP_WIDTH];
	}

	return 0;
}

inline int OnLadder(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	int mapidx=tilemap[w+(h)*MAP_WIDTH]&0xFF;

	if (mapidx==224) return 1;
	if (mapidx==225) return 2;
	if (mapidx==240) return 1;
	if (mapidx==241) return 2;

	return 0;
}

inline int EdgeLeft(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);

	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_UP)==C_UP) {
		return tilemap[w+(h)*MAP_WIDTH];
	}
	
	return 0;
}

inline int EdgeRight(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	
	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_UP)==C_UP) {
		return tilemap[w+(h)*MAP_WIDTH];
	}
	
	return 0;
}

inline int BlockUp(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	
	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_DOWN)==C_DOWN) return tilemap[w+(h)*MAP_WIDTH];
	
	return 0;
}

inline int BlockRight(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	
	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_LEFT)==C_LEFT) return tilemap[w+(h)*MAP_WIDTH];
	
	return 0;
}

inline int BlockLeft(float x,float y) 
{
	uint32 w=((uint32)x);
	uint32 h=((uint32)y);
	
	if ((collmap[tilemap[w+(h)*MAP_WIDTH]&0xFF]&C_RIGHT)==C_RIGHT) return tilemap[w+(h)*MAP_WIDTH];
	
	return 0;
}

inline int EnemyOnGround(int i) 
{
	int retval,count;
	if ((retval=OnGround(enemies[i].pos.x-.5f,enemies[i].pos.z))!=0) {
		enemies[i].pos.z=floorf(enemies[i].pos.z);
		return retval;
	}
	if ((retval=OnGround(enemies[i].pos.x+.5f,enemies[i].pos.z))!=0) {
		enemies[i].pos.z=floorf(enemies[i].pos.z);
		return retval;
	}
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active) {
			if (enemies[i].pos.x>(items[count].pos.x-1.0f) && enemies[i].pos.x<(items[count].pos.x+items[count].width+1.0f)
						&& enemies[i].pos.z>=(items[count].pos.z-items[count].height) && enemies[i].pos.z<=(items[count].pos.z+1)) {//+3 blocks hero height
				enemies[i].pos.z=items[count].pos.z-items[count].height;
				enemies[i].pos.x+=items[count].vel.x;
				return -items[count].type;
			}
		}
	}

	return 0;
}

inline int EnemyEdgeLeft(int i) 
{
	int retval,count;
	if ((retval=EdgeLeft(enemies[i].pos.x-.5f,enemies[i].pos.z))!=0) return retval;
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active) {
			if (enemies[i].pos.x>(items[count].pos.x+0.5f) && enemies[i].pos.x<(items[count].pos.x+items[count].width+1.0f)
						&& enemies[i].pos.z>=(items[count].pos.z-items[count].height) && enemies[i].pos.z<=(items[count].pos.z+1)) {//+3 blocks hero height
//				enemies[i].pos.z=items[count].pos.z-items[count].height;
//				enemies[i].vel.x+=items[count].vel.x;
				return -items[count].type;
			}
		}
	}		
	return 0;
}

inline int EnemyEdgeRight(int i) 
{
	int retval,count;
	if ((retval=EdgeLeft(enemies[i].pos.x+1.5f,enemies[i].pos.z))!=0) return retval;
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active) {
			if (enemies[i].pos.x>(items[count].pos.x-1.0f) && enemies[i].pos.x<(items[count].pos.x+items[count].width-0.5f)
						&& enemies[i].pos.z>=(items[count].pos.z-items[count].height) && enemies[i].pos.z<=(items[count].pos.z+1)) {//+3 blocks hero height
//				enemies[i].pos.z=items[count].pos.z-items[count].height;
//				enemies[i].vel.x+=items[count].vel.x;
				return -items[count].type;
			}
		}
	}		
	return 0;
}

inline int EnemyBlockRight(int i) 
{
	int retval,count;
	if ((retval=BlockRight(enemies[i].pos.x+1.0f,enemies[i].pos.z-1.0f))!=0) return retval;
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active) {
			if (enemies[i].pos.x>=(items[count].pos.x-1.1f) && enemies[i].pos.x<=(items[count].pos.x+1)
						&& enemies[i].pos.z>(items[count].pos.z-items[count].height) && enemies[i].pos.z<(items[count].pos.z+3)) {//+3 blocks hero height
				enemies[i].pos.x=items[count].pos.x-1.1f;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

inline int EnemyBlockLeft(int i) 
{
	int retval,count;
	if ((retval=BlockLeft(enemies[i].pos.x-1.0f,enemies[i].pos.z-1.0f))!=0) return retval;
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active) {
			if (enemies[i].pos.x>=(items[count].pos.x+items[count].width) && enemies[i].pos.x<=(items[count].pos.x+items[count].width+1.1f)
						&& enemies[i].pos.z>(items[count].pos.z-items[count].height) && enemies[i].pos.z<(items[count].pos.z+3)) {//+3 blocks hero height
				enemies[i].pos.x=items[count].pos.x+items[count].width+1.1f;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

inline int HeroInGoal() 
{
	if ((collmap[tilemap[((uint32)(echo.pos.x-.5f))+((uint32)(echo.pos.z-1.0f))*MAP_WIDTH]&0xFF]&C_GOAL)==C_GOAL){
		return 1;
	}
	if ((collmap[tilemap[((uint32)(echo.pos.x-.5f))+((uint32)(echo.pos.z-1.0f))*MAP_WIDTH]&0xFF]&C_GOAL)==C_GOAL){
		return 1;
	}
	return 0;
}

inline int HeroOnGround() 
{
	int retval,i;
	if ((retval=OnGround(echo.pos.x-.5f,echo.pos.z))!=0) {
		echo.pos.z=floorf(echo.pos.z);
		return retval;
	}
	if ((retval=OnGround(echo.pos.x+.5f,echo.pos.z))!=0) {
		echo.pos.z=floorf(echo.pos.z);
		return retval;
	}

	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active) {
			if (echo.pos.x>(items[i].pos.x) && echo.pos.x<(items[i].pos.x+items[i].width+1.0f)
				&& echo.pos.z>=(items[i].pos.z-items[i].height) && echo.pos.z<=(items[i].pos.z-items[i].height+1.0f)) {
				if (items[i].type==1) {//coin
					score+=VALUECOIN;
					items[i].active=0;
					snd_sfx_play(sound_cash, 240, 128 );
				}else{
					echo.pos.z=items[i].pos.z-items[i].height;
					return -items[i].type;
				}
			}
		}
	}
	return 0;
}

inline int HeroBlockUp() 
{
	int retval,i;
	if ((retval=BlockUp(echo.pos.x-.5f,echo.pos.z-4.0f))!=0) return retval;
	if ((retval=BlockUp(echo.pos.x+.5f,echo.pos.z-4.0f))!=0) return retval;
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active) {
			if (echo.pos.x>(items[i].pos.x) && echo.pos.x<(items[i].pos.x+items[i].width+1.0f)
				&& (echo.pos.z-4)>=(items[i].pos.z-1.0f) && (echo.pos.z-4.0f)<=(items[i].pos.z)) {
				if (items[i].type==1) {//coin
					score+=VALUECOIN;
					items[i].active=0;
					snd_sfx_play(sound_cash, 240, 128 );
				}else{
					return -items[i].type;
				}
			}
		}
	}
	return 0;
}

inline int HeroBlockRight() 
{
	int retval,i;
	if ((retval=BlockRight(echo.pos.x+1.0f,echo.pos.z-1.0f))!=0) {
		if (echo.vel.x>0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.2f;
			echo.pushing=1;
		}
		return retval;
	}
	if ((retval=BlockRight(echo.pos.x+1.0f,echo.pos.z-2.0f))!=0) {
		if (echo.vel.x>0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.2f;
			echo.pushing=1;
		}
		return retval;
	}
	if ((retval=BlockRight(echo.pos.x+1.0f,echo.pos.z-3.0f))!=0) {
		if (echo.vel.x>0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.2f;
			echo.pushing=1;
		}
		return retval;
	}
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active) {
			if (echo.pos.x>=(items[i].pos.x-0.31f) && echo.pos.x<=(items[i].pos.x+1.0f)
				&& echo.pos.z>(items[i].pos.z-items[i].height) && echo.pos.z<(items[i].pos.z+3.0f)) {//+3 blocks hero height
				if (echo.vel.x>0) {
					if (items[i].type==1) {//coin
						score+=VALUECOIN;
						items[i].active=0;
						snd_sfx_play(sound_cash, 240, 128 );
					}else{
						if (items[i].pushable && items[i].movableright) {
							echo.vel.x/=1.5f;
							items[i].vel.x=echo.vel.x;
							echo.pos.x=items[i].pos.x+items[i].vel.x-0.3f;
							if (echo.pushing==0 && items[i].type==2 && echo.jumping==0) snd_sfx_play(sound_slide, 240, 128 );
							echo.pushing=1;
						}else{
							echo.vel.x=0;
							echo.pos.x=items[i].pos.x-0.3f;
							echo.pushing=1;
						}
						return -items[i].type;
					}
				}
			}
		}
	}
	return 0;
}

inline int HeroBlockLeft() 
{
	int retval,i;
	if ((retval=BlockLeft(echo.pos.x-1.0f,echo.pos.z-1.0f))!=0) {
		if (echo.vel.x<0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.8f;
			echo.pushing=1;
		}
		return retval;
	}
	if ((retval=BlockLeft(echo.pos.x-1.0f,echo.pos.z-2.0f))!=0) {
		if (echo.vel.x<0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.8f;
			echo.pushing=1;
		}
		return retval;
	}
	if ((retval=BlockLeft(echo.pos.x-1.0f,echo.pos.z-3.0f))!=0) {
		if (echo.vel.x<0) {
			echo.vel.x=0;
			echo.pos.x=floorf(echo.pos.x)+.8f;
			echo.pushing=1;
		}
		return retval;
	}
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active) {
			if (echo.pos.x>=(items[i].pos.x+items[i].width) && echo.pos.x<=(items[i].pos.x+items[i].width+1.31f)
				&& echo.pos.z>(items[i].pos.z-items[i].height) && echo.pos.z<(items[i].pos.z+3.0f)) {//+3 blocks hero height
				if (echo.vel.x<0.0f) {
					if (items[i].type==1) {//coin
						score+=VALUECOIN;
						items[i].active=0;
						snd_sfx_play(sound_cash, 240, 128 );
					}else{
						if (items[i].pushable && items[i].movableleft) {
							echo.vel.x/=1.5f;
							items[i].vel.x=echo.vel.x;
							echo.pos.x=items[i].pos.x+items[i].vel.x+items[i].width+1.3f;
							if (echo.pushing==0 && items[i].type==2 && echo.jumping==0) snd_sfx_play(sound_slide, 240, 128 );
							echo.pushing=1;
						}else{
							echo.vel.x=0;
							echo.pos.x=items[i].pos.x+items[i].width+1.3f;
							echo.pushing=1;
						}
						return -items[i].type;
					}
				}
			}
		}
	}
	return 0;
}

inline int ItemOnGround(int i) 
{
	int retval,count;
	for (count=0;count<(int)items[i].width;count++) {
		if ((retval=OnGround(items[i].pos.x+((float)count)+1.0f,items[i].pos.z))!=0) {
			items[i].pos.z=floorf(items[i].pos.z);
			return retval;
		}
	}
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active && i!=count) {
			if (items[i].pos.x>(items[count].pos.x-items[i].width) && items[i].pos.x<(items[count].pos.x+items[count].width)
						&& items[i].pos.z>=(items[count].pos.z-items[count].height) && items[i].pos.z<=(items[count].pos.z-items[count].height+1)) {//+3 blocks hero height
				items[i].pos.z=items[count].pos.z-items[count].height;
				items[i].vel.x+=items[count].vel.x;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

inline int ItemBlockUp(int i) 
{
	int retval,count;
	if ((retval=BlockUp(items[i].pos.x+1.0f,items[i].pos.z-items[i].height))!=0) return retval;
	if ((retval=BlockUp(items[i].pos.x+items[i].width,items[i].pos.z-items[i].height))!=0) return retval;
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active && i!=count) {
			if (items[i].pos.x>(items[count].pos.x-items[i].width) && items[i].pos.x<(items[count].pos.x+items[count].width)
						&& items[i].pos.z>=(items[count].pos.z+items[i].height-1) && items[i].pos.z<=(items[count].pos.z+items[i].height)) {//+3 blocks hero height
				items[count].pos.z=items[i].pos.z-items[i].height;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

inline int ItemBlockRight(int i) 
{
	int retval,count;
	if ((retval=BlockRight(items[i].pos.x+items[i].width+.5f,items[i].pos.z-1.0f))!=0) {
		items[i].pos.x=floorf(items[i].pos.x)+.51f;
		return retval;
	}
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active && i!=count) {
			if (items[i].pos.x>=(items[count].pos.x-items[i].width) && items[i].pos.x<=(items[count].pos.x+1.0f)
						&& items[i].pos.z>(items[count].pos.z-items[count].height+1.0f) && items[i].pos.z<(items[count].pos.z+items[i].height)) {
				items[i].pos.x=items[count].pos.x-items[i].width;
				if (items[i].vel.x>0) items[i].vel.x=0;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

inline int ItemBlockLeft(int i) 
{
	int retval,count;
	if ((retval=BlockLeft(items[i].pos.x+.5f,items[i].pos.z-1.0f))!=0) {
		items[i].pos.x=floorf(items[i].pos.x)+.49f;
		return retval;
	}
	for (count=0;count<ITEMCOUNT;count++) {
		if (items[count].active && i!=count) {
			if (items[i].pos.x>=(items[count].pos.x+items[count].width-1.0f) && items[i].pos.x<=(items[count].pos.x+items[count].width)
						&& items[i].pos.z>(items[count].pos.z-items[count].height+1.0f) && items[i].pos.z<(items[count].pos.z+items[i].height)) {
				items[i].pos.x=items[count].pos.x+items[count].width;
				if (items[i].vel.x<0.0f) items[i].vel.x=0.0f;
				return -items[count].type;
			}
		}
	}	
	return 0;
}

void drawtiles() {
	int x,y,sx=(int)cam.x,sy=(int)cam.z;
//	glPushMatrix();
//	glScalef(2.0f, 2.0f, 2.0f);
//	glBegin(GL_QUADS);
	if (cam.ry>0.0f) {
		for (x=-20;x<24;x++) {
			for (y=-15;y<19;y++) {
				if (tilemap[(sx+x)+((sy-y)*MAP_WIDTH)]!=0) {
					if ((sx+x)>=0 && (sy-y)>=0 && (sx+x)<MAP_WIDTH && (sy-y)<MAP_HEIGHT) {
						glPushMatrix();
						glTranslatef((float)(sx+x),0,(float)(-sy+y));
						draw_tgm_byID(&mod_tiles,(uint32*)tex_tile,tilemap[(sx+x)+((sy-y)*MAP_WIDTH)],TEXCOUNT);
						glPopMatrix();
					}
				}
			}
		}
	}else{
		for (x=-26;x<18;x++) {
			for (y=-15;y<19;y++) {
				if (tilemap[(sx+x)+((sy-y)*MAP_WIDTH)]!=0) {
					if ((sx+x)>=0 && (sy-y)>=0 && (sx+x)<MAP_WIDTH && (sy-y)<MAP_HEIGHT) {
						glPushMatrix();
						glTranslatef((float)(sx+x),0,(float)(-sy+y));
						draw_tgm_byID(&mod_tiles,(uint32*)tex_tile,tilemap[(sx+x)+((sy-y)*MAP_WIDTH)],TEXCOUNT);
						glPopMatrix();
					}
				}
			}
		}
	}
//	glEnd();
//	glPopMatrix();
}

void DrawEnemies() {
	int i,vol,pan;
	glBindTexture( GL_TEXTURE_2D, tex_pgun);
	CommonTexParams();
	for (i=0;i<ENEMYCOUNT;i++) {
		if (enemies[i].active==1) {
			enemies[i].curFrame+=1;
			if (enemies[i].exploding) {
				if (enemies[i].curFrame>=PGUNEXPLEND) {
					enemies[i].curFrame=PGUNWALKSTART;
					enemies[i].active=0;
					enemies[i].exploding=0;
				}
			}else{//only draw if not exploding
				if (enemies[i].curFrame>=PGUNWALKEND) enemies[i].curFrame=PGUNWALKSTART;
			}
			mod_pgun.curFrame=enemies[i].curFrame;
			UpdateAnim(&mod_pgun);
			if (enemies[i].active==1) {//enemy may have become inactive
				if (cam.ry>0.0f) {
					if (enemies[i].pos.x>cam.x-20 && enemies[i].pos.x<cam.x+24) {
						pan=128+(int)(4.9f*(enemies[i].pos.x-echo.pos.x));
						vol=255-(int)fabs(9.8f*(enemies[i].pos.x-echo.pos.x));
						if (mod_pgun.curFrame==0 || mod_pgun.curFrame==18) snd_sfx_play(sound_tick, vol, pan );

						glPushMatrix();
						glTranslatef(enemies[i].pos.x,0,-enemies[i].pos.z+.5f);
						glScalef(0.4f, 0.4f, 0.4f);
						if (enemies[i].flip) glRotatef(180, 0.0f, 0.0f, 1.0f);
						draw_agm(&mod_pgun);
						glPopMatrix();
					}	
				}else{
					if (enemies[i].pos.x>cam.x-26 && enemies[i].pos.x<cam.x+18) {
						pan=128+(int)(4.9f*(enemies[i].pos.x-echo.pos.x));
						vol=255-(int)fabs(9.8f*(enemies[i].pos.x-echo.pos.x));
						if (mod_pgun.curFrame==0 || mod_pgun.curFrame==18) snd_sfx_play(sound_tick, vol, pan );

						glPushMatrix();
						glTranslatef(enemies[i].pos.x,0,-enemies[i].pos.z+.5f);
						glScalef(0.4f, 0.4f, 0.4f);
						if (enemies[i].flip) glRotatef(180, 0.0f, 0.0f, 1.0f);
						draw_agm(&mod_pgun);
						glPopMatrix();
					}
				}
			}
		}
	}
}

void DrawItems() {
	int i;
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active==1) {
			if (cam.ry>0.0f) {
				if (items[i].pos.x>cam.x-20.0f && items[i].pos.x<cam.x+24.0f) {
					glPushMatrix();
					glTranslatef(items[i].pos.x,0,-items[i].pos.z+.5f);
					draw_tgm_byID(&mod_items,(uint32*)tex_tile,items[i].model,TEXCOUNT);
					glPopMatrix();
				}	
			}else{
				if (items[i].pos.x>cam.x-26.0f && items[i].pos.x<cam.x+18.0f) {
					glPushMatrix();
					glTranslatef(items[i].pos.x,0,-items[i].pos.z+.5f);
					draw_tgm_byID(&mod_items,(uint32*)tex_tile,items[i].model,TEXCOUNT);
					glPopMatrix();
				}
			}
		}
	}
}

void DrawScene() {
		/* Begin frame */
	glKosBeginFrame();

	glLoadIdentity();
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

	glPushMatrix();

		cam.x=echo.pos.x;
//		cam.z=(8*cam.z+( (echo.pos.z>(MAP_WIDTH-(cam.zoom*.6))) ? (MAP_WIDTH-(cam.zoom*.6)) : (echo.pos.z<(cam.zoom*.6)) ? (cam.zoom*.6) : echo.pos.z) )/9;
		cam.z=(8*cam.z+echo.pos.z)/9;
		if (cam.z>(MAP_HEIGHT-(cam.zoom*.15f))) cam.z=(MAP_HEIGHT-(cam.zoom*.15f));
		if (cam.z<(cam.zoom*.2f)) cam.z=(cam.zoom*.2f);

		if (cam.x<(cam.zoom*.4f)) cam.x=(cam.zoom*.4f);
		if (cam.x>(MAP_WIDTH-(cam.zoom*.4f))) cam.x=(MAP_WIDTH-(cam.zoom*.4f));
		glRotatef(-90, 1.0f, 0.0f, 0.0f);

		glRotatef(3.0f, 1.0f, 0.0f, 0.0f);

		glTranslatef(0, cam.zoom, -4);

		glRotatef(cam.ry, 0.0f, 0.0f, 1.0f);

		glPushMatrix();
			glScalef(0.5f, 0.5f, 0.5f);
			glRotatef(90, 0.0f, 0.0f, 1.0f);
			glBindTexture( GL_TEXTURE_2D, tex_sky);
			CommonTexParams();
			draw_agm(&mod_sky);
		glPopMatrix();
	
		glTranslatef(-cam.x, 0 , cam.z);

		glPushMatrix();
			glTranslatef(0, 0 , -48.5);
//			glEnable(GL_KOS_VFZ_CLIPPING);
			draw_tgm(&mod_ground,(uint32*)tex_ground); 
//			glDisable(GL_KOS_VFZ_CLIPPING);
//			drawfloor((int)cam.x);
		glPopMatrix();
	

		glDisable(GL_CULL_FACE);
		glPushMatrix();
			glTranslatef(echo.pos.x-0.5f, 0.0f,-echo.pos.z+0.5f);
			glScalef(0.4f, 0.4f, 0.4f);
			if(echo.movemode==MMCLIMB) {
				glRotatef(180, 0.0f, 0.0f, 1.0f);
			}else{
				if (inactivetime>MAXINACTIVETIME) {
					inactivetime=MAXINACTIVETIME;
				}else{
					glRotatef(90*(float)echo.flip, 0.0f, 0.0f, 1.0f);
				}
			}
			if (blinkcount<0) {
				if (blinkcount<-BLINKTIME) blinkcount=rand()%100;
				blinkcount--;
				glBindTexture( GL_TEXTURE_2D, tex_echoblink);
			}else{
				glBindTexture( GL_TEXTURE_2D, tex_echo);
				blinkcount--;
			}
			CommonTexParams();
			draw_agm(&mod_echo);
		glPopMatrix();

		DrawEnemies();
		glEnable(GL_CULL_FACE);

		DrawItems();


//		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glBindTexture( GL_TEXTURE_2D, tex_tile[0]);
		CommonTexParams();
		drawtiles();
	glPopMatrix();


	glKosFinishList(); 

	if (showpanel) {
		glBindTexture( GL_TEXTURE_2D, tex_panel);
		CommonTexParams();
		DrawPanel(score,lives);
	}

	/* Finish the frame */
	glKosFinishFrame();
}


int readmovie()
{
	uint32	f;
	int	i;
	char destfn[]=ROMDISKDIR "echomov.dat";
	movieheadertype header;


	/* Open output file */
	f = fs_open(destfn, O_RDONLY);
	if (!f) {
		DBGOUT("can't read movie file");
		return -1;
	}

	/* Write the data */
	fs_read(f, (void*)&header, sizeof(header));

	if (header.Magic!=MOVIEMAGIC) {
		DBGOUT("invalid movie file");
		return -1;
	}
	currentmaxmovietime=header.framecount;
	if (currentmaxmovietime>=MAXMOVIETIME) currentmaxmovietime=MAXMOVIETIME-1;

	for (i=0;i<=currentmaxmovietime;i++) {
		fs_read(f, (void*)&moviecond[i], sizeof(moviecond[i]) );
	}

	fs_close(f);

	return 0;
}

#ifdef MOVIEMAKER
int writemovie()
{
	file_t	f;
	int	i;
	char destfn[]="/pc/echomov.dat";
	movieheadertype header;
	header.Magic=MOVIEMAGIC;
	header.framecount=currentmaxmovietime;

	/* Open output file */
	f = fs_open(destfn, O_WRONLY | O_TRUNC);
	if (!f) {
		DBGOUT("can't write movie file");
		return -1;
	}

	/* Write the data */
	fs_write(f, (void*)&header, sizeof(header));
	for (i=0;i<header.framecount;i++) {
		fs_write(f, (void*)&moviecond[i], sizeof(moviecond[i]) );
	}

	fs_close(f);
	DBGOUT("wrote movie file");

	return 0;
}
#endif

//return 0-normal  1-restart level 2-next level 3-quit
int CheckInput() {
	int Upblock,GroundBlock,Ladder1,Ladder2;
	float climbdir=0;
	echo.movemode=MMSTAND;
	if (cont_get_cond(c, &cond) < 0) {
		DBGOUT("Error reading controller\n");
		return 3;
	}
	
	if (!(cond.buttons & CONT_START) && !(cond.buttons & CONT_Y))
		return 3;
	if (!(cond.buttons & CONT_START)) {
#ifdef MOVIEMAKER
		if (playmovie) DBGOUT("movie stopping\r\n");
		if (recordmovie) DBGOUT("movie record stopping\r\n");
#endif
		playmovie=0;
		recordmovie=0;
		movietime=0;
		return 1;
	}

#ifdef SCREENSHOTMAKER
	if (!(cond.buttons & CONT_X)) {
		if (button==0) takeshot=1;
		button=1;
	}else{
		button=0;
	}
#endif

#ifdef MOVIEMAKER
	if (!(cond.buttons & CONT_X)) {
		playmovie=1;
		if (recordmovie) writemovie();
		recordmovie=0;
		movietime=0;
		DBGOUT("play movie\r\n");
		return 1;
	}
	if (!(cond.buttons & CONT_Y)) {
		recordmovie=1;
		playmovie=0;
		movietime=0;
		currentmaxmovietime=0;
		DBGOUT("record movie\r\n");
		return 1;
	}
	if (recordmovie) {
		moviecond[movietime]=cond.buttons;
		if (currentmaxmovietime<movietime) currentmaxmovietime=movietime;
		movietime++;
		if (movietime>=MAXMOVIETIME) {
			recordmovie=0;
			DBGOUT("maximum movie time - record ending\r\n");
		}
	}
#endif

	if (playmovie) {
		cond.buttons=moviecond[movietime];
		if (movietime>=MAXMOVIETIME-1 || movietime>=currentmaxmovietime) {
			movietime=currentmaxmovietime;
			cond.buttons=0xFFFF;
			inactivetime=MAXINACTIVETIME;
//			resetlevel();
//			return 1;
		}else{
			movietime++;
		}
	}
	

	inactivetime++;
	if (cond.buttons!=0xFFFF) {
		inactivetime=0;
	}
		
	if (echo.dying==0) {
	//	cam.ry+=(128-(float)cond.joyx)*.05f;

		if (!(cond.buttons & CONT_DPAD_LEFT)) {
			echo.flip=-1;
			echo.vel.x-=RUNVELX;
			echo.climbing=0;
			if (!echo.jumping) {
				if (echo.pushing) echo.movemode=MMPUSH;
				else echo.movemode=MMJOG;
			}
		}else if (!(cond.buttons & CONT_DPAD_RIGHT)) {
			echo.flip=1;
			echo.vel.x+=RUNVELX;
			echo.climbing=0;
			if (!echo.jumping) {
				if (echo.pushing) echo.movemode=MMPUSH;
				else echo.movemode=MMJOG;
			}			
		}else{//neither left or right means standing still
			echo.pushing=0;
		}

		if (!(cond.buttons & CONT_A)) {
			if (echo.canjump && !echo.jumping ) {
				echo.movemode=MMJUMP;
				mod_echo.curFrame=JUMPSTART;
				echo.jumping=1;
				echo.jumppush=1;
				echo.canjump=0;
				snd_sfx_play(sound_jump, 130, 128 );
			}
			if (echo.jumppush && mod_echo.curFrame<(JUMPSTART+JUMPACCTIME) && mod_echo.curFrame>=JUMPSTART) {
				echo.vel.z=JUMPVEL;
				echo.pos.z+=echo.vel.z;	
			}else{
				echo.jumppush=0;
			}
		}

		Ladder1=OnLadder(echo.pos.x-.5f,echo.pos.z-1);
		Ladder2=OnLadder(echo.pos.x+.5f,echo.pos.z-1);
		if (Ladder1 || Ladder2) { 
			if (!(cond.buttons & CONT_DPAD_UP)) {
				climbdir=1;
				echo.climbing=1;
				if (cond.buttons & CONT_A) {
					echo.canjump=1;
					echo.jumping=0;
					echo.jumppush=0;
				}
			}else if (!(cond.buttons & CONT_DPAD_DOWN)) {
				climbdir=-1;
				echo.climbing=1;
				if (cond.buttons & CONT_A) {
					echo.canjump=1;
					echo.jumping=0;
					echo.jumppush=0;
				}
			}else climbdir=0;
			if (echo.climbing) {
				if (Ladder1==1) {
					echo.pos.x=floorf(echo.pos.x);
				}
				if (Ladder1==2) {
					echo.pos.x=floorf(echo.pos.x)-1;
				}
				if (Ladder2==1) {
					echo.pos.x=floorf(echo.pos.x)+1;
				}
				echo.movemode=MMCLIMB;
			}
		}	
	
	}//if dying block unput

	if (echo.vel.x>MAXVELX) echo.vel.x=MAXVELX;
	if (echo.vel.x<-MAXVELX) echo.vel.x=-MAXVELX;

	GroundBlock=HeroOnGround();
	Upblock=HeroBlockUp();

	if (echo.dying==0) {
		switch(GroundBlock) {
			case 208:
			case 210:
			case 211:
			case 192:
			case 194:
			case 195:
				echo.dying=1;
				mod_echo.curFrame=DIESTART;
				snd_sfx_play(sound_die, 255, 128 );//enemy has killed you!
				lives-=1;
				break;
		}
	}
	if (HeroBlockRight()!=0 && echo.vel.x>0) {
		echo.vel.x=0.0f;
	}
	if (HeroBlockLeft()!=0 && echo.vel.x<0) {
		echo.vel.x=0.0f;
	}
	if (HeroInGoal()) return 2;
	if (echo.movemode==MMCLIMB && echo.jumping==0 && (GroundBlock==0 || climbdir>=0)) {
		Ladder1=OnLadder(echo.pos.x-.5f,echo.pos.z-(1+CLIMBSPEED));
		Ladder2=OnLadder(echo.pos.x+.5f,echo.pos.z-(1+CLIMBSPEED));
		if ((Ladder1 || Ladder2) || climbdir<0)	{
			echo.pos.z-=climbdir*CLIMBSPEED;//don't climb higher than top of ladder
		}else{
			climbdir=0;
		}
		if (GroundBlock && climbdir<0)	{
			climbdir=0;
		}
		mod_echo.curFrame=(float)(CLIMBEND-((int)(echo.pos.z*10-1))%20);
		echo.vel.z=0;
		echo.jumping=0;
	}else{
		echo.climbing=0;
		if (GroundBlock!=0) {
			echo.pos.x+=echo.vel.x;
			echo.vel.x=FLOAT0CLIP(echo.vel.x*frictionmap[GroundBlock&0xFF]);
			echo.vel.z=0;
			if (echo.jumping==1) snd_sfx_play(sound_land, 240, 128 );
			if (cond.buttons & CONT_A) echo.canjump=1;
			echo.jumping=0;
			echo.jumppush=0;
		}else{
			echo.vel.z+=GRAVITY;
			if (Upblock!=0) {
				if (echo.vel.z<0) {//only hit things going up
					snd_sfx_play(sound_bumpup, 240, 128 );
					if (Upblock==44 || Upblock==45) {
						SwitchBlocks(1);
					}
					if (Upblock==300 || Upblock==301) {
						SwitchBlocks(0);
					}
					if (Upblock==112 || Upblock==113) {
						ItemBlocks();
					}
					echo.vel.z=.01f;//bump up
				}
				echo.canjump=0;
				echo.jumppush=0;
			}else{
				if (echo.vel.z>TERMVEL) echo.vel.z=TERMVEL;//terminal velocity
			}
			echo.jumping=1;
			echo.pos.z+=echo.vel.z;
			echo.pos.x+=echo.vel.x;
			echo.vel.x=FLOAT0CLIP(echo.vel.x*AIRFRICTION);
		}
	}
	if (echo.pos.z<0) echo.pos.z=0;

	//these modes take priority
	if (echo.jumping==1) {
		echo.pushing=0;
		echo.movemode=MMJUMP;
	}
	if (echo.dying==1) echo.movemode=MMDIE;

	if(echo.movemode==MMCLIMB) {
		cam.ry=FLOAT0CLIP( ((20*cam.ry)*(1.0f/21.0f)) );
	}else {
		cam.ry=FLOAT0CLIP( ((20*cam.ry+(float)echo.flip*20)*(1.0f/21.0f)) );
	}
	
	cam.zoom=FLOAT0CLIP( ( (10*cam.zoom+ (40-((float)cond.rtrig)/20) )*(1.0f/11.0f)) );

	if (echo.movemode!=MMCLIMB) {
		mod_echo.curFrame+=1;
	}

	if (echo.movemode==MMSTAND) {
		if (mod_echo.curFrame>STDEND) mod_echo.curFrame=STDSTART;
		if (mod_echo.curFrame<STDSTART) mod_echo.curFrame=STDSTART;
	}else if (echo.movemode==MMJOG) {
		if (mod_echo.curFrame>JOGEND) mod_echo.curFrame=JOGSTART;
		if (mod_echo.curFrame<JOGSTART) mod_echo.curFrame=JOGSTART;

		if (mod_echo.curFrame==JOGSTART) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame==JOGMID) snd_sfx_play(sound_walk, 140, 128 );
	}else if (echo.movemode==MMPUSH) {
		if (mod_echo.curFrame>PUSHEND) mod_echo.curFrame=PUSHSTART;
		if (mod_echo.curFrame<PUSHSTART) mod_echo.curFrame=PUSHSTART;

		if (mod_echo.curFrame==PUSHSTART) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame==PUSHMID) snd_sfx_play(sound_walk, 140, 128 );
	}else if (echo.movemode==MMJUMP) {
		if (mod_echo.curFrame>JUMPEND) mod_echo.curFrame=JUMPEND;
		if (mod_echo.curFrame<JUMPSTART) mod_echo.curFrame=JUMPSTART;
	}else if (echo.movemode==MMCLIMB) {
		if (mod_echo.curFrame>CLIMBEND) mod_echo.curFrame=CLIMBSTART;
		if (mod_echo.curFrame<CLIMBSTART) mod_echo.curFrame=CLIMBEND;
		if (mod_echo.curFrame>=CLIMBSTART && mod_echo.curFrame<=CLIMBSTART+1.0f && climbdir!=0) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame>=CLIMBMID && mod_echo.curFrame<=CLIMBMID+1.0f && climbdir!=0) snd_sfx_play(sound_walk, 140, 128 );
	}else  if (echo.movemode==MMDIE) {
		if (mod_echo.curFrame>DIEEND) {
			mod_echo.curFrame=DIEEND;
			if (lives>0) restartlevel();
			else return 1;
		}
		if (mod_echo.curFrame<DIESTART) mod_echo.curFrame=DIESTART;
	}
	UpdateAnim(&mod_echo);

	return 0;
}

void EnemyUpdateAI()
{
	int i,BR,BL;
	glBindTexture( GL_TEXTURE_2D, tex_pgun);
	CommonTexParams();
	for (i=0;i<ENEMYCOUNT;i++) {
		if (enemies[i].active==1 && enemies[i].exploding==0) {
			BL=EnemyBlockLeft(i);
			BR=EnemyBlockRight(i);
			if (enemies[i].flip==1 && BL!=0) {
				enemies[i].flip=0;
			}
			if (enemies[i].flip==0 && BR!=0) {
				enemies[i].flip=1;
			}
			if (BL!=0 && BR!=0) {//squeeze play-kill enemy by smashing
				enemies[i].exploding=1;
				enemies[i].curFrame=PGUNEXPLSTART;
				snd_sfx_play(sound_explode, 255, 128 );
				score+=VALUEPGUN;
			}
			if (EnemyOnGround(i)) {
				if (enemies[i].flip==1 && EnemyEdgeLeft(i)==0) {
					enemies[i].flip=0;
				}
				if (enemies[i].flip==0 && EnemyEdgeRight(i)==0) {
					enemies[i].flip=1;
				}
			}else{
				enemies[i].pos.z+=.2f;
			}
			if (enemies[i].flip==1) {
				enemies[i].pos.x+=(-.2f);
			}else{
				enemies[i].pos.x+=(.2f);
			}
		}
	}

}

void ItemUpdate()
{
	int i,vol,pan;
	glBindTexture( GL_TEXTURE_2D, tex_pgun);
	CommonTexParams();
	for (i=0;i<ITEMCOUNT;i++) {
		if (items[i].active) {
			if (items[i].usegravity) {
				items[i].vel.z+=GRAVITY;
				if (items[i].vel.z>TERMVEL) items[i].vel.z=TERMVEL; 
				if (ItemOnGround(i)!=0 && items[i].vel.z>0) {
					if (items[i].bounce) {
						items[i].vel.z=FLOAT0CLIP(-items[i].vel.z*BOUNCEFRICTION);
					}else{
						items[i].vel.z=0.0f;
					}
					if (items[i].pos.x>echo.pos.x-25.0f && items[i].pos.x<echo.pos.x+25.0f && items[i].type==1) {
						vol=255-(int)fabs(10.0f*(items[i].pos.x-echo.pos.x));
						pan=128+(int)(5.0f*((items[i].pos.x+2.0f)-echo.pos.x));
						snd_sfx_play(sound_coin, vol, pan);
					}
				}//onground
				if (ItemBlockUp(i)!=0.0f && items[i].vel.z<0.0f) {
					if (items[i].bounce) {
						items[i].vel.z=FLOAT0CLIP(-items[i].vel.z*BOUNCEFRICTION);
					}else{
						items[i].vel.z=0;
					}
					if (items[i].pos.x>echo.pos.x-25.0f && items[i].pos.x<echo.pos.x+25.0f && items[i].type==1) {
						vol=255-(int)fabs(10*(items[i].pos.x-echo.pos.x));
						pan=128+(int)(5*((items[i].pos.x+2)-echo.pos.x));
						snd_sfx_play(sound_coin, vol, pan);
					}
				}//blockup
			}//grav
			if (items[i].pushable) {
				if (ItemBlockRight(i)!=0) {
					if (items[i].movableright==1 && items[i].type==2) snd_sfx_play(sound_bumpbox, 240, 128 );
					items[i].movableright=0;
				}else{
					items[i].movableright=1;
				}
				if (ItemBlockLeft(i)!=0) {
					if (items[i].movableleft==1 && items[i].type==2) snd_sfx_play(sound_bumpbox, 240, 128 );
					items[i].movableleft=0;
				}else{
					items[i].movableleft=1;
				}
			}//pushable
			items[i].pos.x+=items[i].vel.x;
			items[i].pos.z+=items[i].vel.z;
		}//active items
	}//for item loop
	for (i=0;i<ITEMCOUNT;i++) {
		items[i].vel.x=0;
	};
}

//return 1-exit level 2-next level 3-quit
int rungame(int lev,char playmov,char panel,int *life,int *scores) {
	int timediff=0,In,framecount=0;
	struct timeval tvoldtime,tvnewtime;
	struct timezone newtimezone;

	gettimeofday(&tvoldtime, &newtimezone);
	gettimeofday(&tvnewtime, &newtimezone);


	loadlevel=lev;
	playmovie=playmov;
	showpanel=panel;
	lives=*life;
	score=*scores;

	initgame();
	if (playmovie) readmovie();


	In=0;
	while(1) {
		/* Check key status */

		if (SystemUpdate()) {In=3;break;}

		In=CheckInput();
		if (In!=0) break;

		//delay state change by one frame
		
/*		curtime = rtc[1]&0xFFFF;//timer_count(TMU0);
		if (curtime!=oldtime) {
			DBGOUT("%d\r\n",(int)framecount);
			framecount=0;

		}
		oldtime=curtime;

*/		framecount++;

//		sprintf(string,"x:%f z%f",echo.pos.x,echo.pos.z);
//		SetWindowText(hWnd,string);

		mod_pgun.curFrame+=1;
		if (mod_pgun.curFrame>PGUNWALKEND) mod_pgun.curFrame=PGUNWALKSTART;
		UpdateAnim(&mod_pgun);

		EnemyUpdateAI();
		OnEnemyHead();

		ItemUpdate();
		DrawScene();
		#ifdef SCREENSHOTMAKER
		if (takeshot) {
			vid_screen_shot("/pc/capture.ppm");
			takeshot=0;
		}
		#endif

		gettimeofday(&tvnewtime, &newtimezone);
		timediff=(tvnewtime.tv_usec/1000) -(tvoldtime.tv_usec/1000);
		if (timediff<0) timediff+=1000;
		while ((timediff)<30) {
			if (SystemUpdate()) {In=3;killgame();return 3;}
			gettimeofday(&tvnewtime, &newtimezone);
			timediff=(tvnewtime.tv_usec/1000) -(tvoldtime.tv_usec/1000);
			if (timediff<0) timediff+=1000;
		}
		tvoldtime.tv_sec=tvnewtime.tv_sec;
		tvoldtime.tv_usec=tvnewtime.tv_usec;

	}
//	sndoggvorbis_stop();
  //  sndoggvorbis_shutdown();

	killgame();

	*life=lives;
	*scores=score;
	
	return In;

}



